package cn.taketoday.live.utils;

import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 * @author TODAY
 */
public abstract class HttpUtils {
  private static final OkHttpClient okHttpClient;

  // MEDIA_TYPE <==> Content-Type
  private static final int READ_TIMEOUT = 15;
  private static final int CONNECT_TIMEOUT = 15;
  private static final int WRITE_TIMEOUT = 15;
  private static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
  // MEDIA_TYPE_TEXT
  // post请求不是application/x-www-form-urlencoded的，全部直接返回，不作处理，即不会解析表单数据来放到request
  // parameter map中。所以通过request.getParameter(name)是获取不到的。只能使用最原始的方式，读取输入流来获取。
  private static final MediaType MEDIA_TYPE_TEXT = MediaType
          .parse("application/x-www-form-urlencoded; charset=utf-8");

  static {
    OkHttpClient.Builder builder = new OkHttpClient.Builder();
    builder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
    builder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
    builder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
    okHttpClient = builder.build();
  }

  public static Response get(
          String url, Map<String, String> headers, Map<String, String> params) throws IOException {
    if (!CollectionUtils.isEmpty(params)) {
      StringBuilder builder = new StringBuilder(100);
      builder.append('?');
      for (Entry<String, String> entry : params.entrySet()) {
        builder.append(entry.getKey())
                .append('=')
                .append(entry.getValue())
                .append('&');
      }
      builder.delete(builder.length() - 1, builder.length());
      url = builder.insert(0, url).toString();
    }

    var builder = new Request.Builder()
            .url(url)
            .get();
    if (!CollectionUtils.isEmpty(headers)) {
      builder.headers(Headers.of(headers));
    }
    return okHttpClient.newCall(builder.build()).execute();
  }

  public static String getString(
          String url, Map<String, String> headers, Map<String, String> params) throws IOException {
    return toString(get(url, headers, params));
  }

  public static Response post(String url, Map<String, String> headers, String json) throws IOException {
    RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, json);
    return post(url, headers, body);
  }

  public static Response post(String url, Map<String, String> headers, Object object) throws IOException {
    return post(url, headers, ObjectUtils.toJSON(object));
  }

  public static Response post(
          String url, Map<String, String> headers, Map<String, String> params) throws IOException {
    StringBuilder content = new StringBuilder();

    Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();
    while (iterator.hasNext()) {
      Map.Entry<String, String> entry = iterator.next();
      content.append(entry.getKey()).append('=').append(entry.getValue());
      if (iterator.hasNext()) {
        content.append('&');
      }
    }
    return post(url, headers, RequestBody.create(MEDIA_TYPE_TEXT, content.toString()));
  }

  public static Response post(
          String url, Map<String, String> headers, RequestBody body) throws IOException {
    var builder = new Request.Builder()
            .url(url)
            .post(body);
    if (!CollectionUtils.isEmpty(headers)) {
      builder.headers(Headers.of(headers));
    }
    return okHttpClient.newCall(builder.build()).execute();
  }

  public static String postString(
          String url, Map<String, String> headers, RequestBody body) throws IOException {
    return toString(post(url, headers, body));
  }

  public static String postString(
          String url, Map<String, String> headers, Object body) throws IOException {
    return toString(post(url, headers, body));
  }

  public static String postString(
          String url, Map<String, String> headers, String body) throws IOException {
    return toString(post(url, headers, body));
  }

  public static String postString(
          String url, Map<String, String> headers, Map<String, String> params) throws IOException {
    return toString(post(url, headers, params));
  }

  public static String toString(Response response) throws IOException {
    final ResponseBody responseBody = response.body();
    if (responseBody == null) {
      return null;
    }
    return responseBody.string();
  }

}
